package fr.resasante.spring3.controller;

import java.util.Locale;

import javax.naming.NamingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.tanesha.recaptcha.ReCaptchaImpl;
import net.tanesha.recaptcha.ReCaptchaResponse;

import org.apache.commons.beanutils.BeanUtils;
import org.jboss.logging.Logger;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

import fr.resasante.ejb.dto.User;
import fr.resasante.ejb.service.UserServiceRemote;
import fr.resasante.ejb.utils.EjbResponse;
import fr.resasante.exception.ApplicationException;
import fr.resasante.spring3.controller.common.ControllerAbstract;
import fr.resasante.spring3.controller.view.CommonView;
import fr.resasante.spring3.controller.view.RegisterView;
import fr.resasante.spring3.form.UserForm;
import fr.resasante.utils.CommonUtils;
import fr.resasante.utils.PropertiesUtils;
import fr.resasante.utils.ServicesUtils;

/**
 * Controller for registration
 * 
 * @author GEFFROY-DE-VILLEBLAN
 * 
 */
@Controller
@SessionAttributes
public class RegisterController extends ControllerAbstract {
	/**
	 * Logger for the class
	 */
	private static final Logger logger = Logger.getLogger(RegisterController.class.getName());

	/**
	 * Add a patient
	 * 
	 * @param userForm
	 *            The patient user object
	 * @param request
	 *            The request
	 * @param locale
	 *            The locale
	 * @return The view
	 * @throws ApplicationException
	 */
	@RequestMapping(value = "/add/patient", method = RequestMethod.POST)
	@PreAuthorize("isAnonymous()")
	public ModelAndView addPatient(UserForm userForm, HttpServletRequest request, Locale locale)
			throws ApplicationException {
		if (!checkCaptcha(request)) {
			return RegisterView.getInstance().getRegisterPatientView(userForm, true);
		}
		final User user = new User();
		EjbResponse ejbResponse = null;
		try {
			// Call the service for adding an user
			BeanUtils.copyProperties(user, userForm);
			UserServiceRemote service = null;
			service = (UserServiceRemote) ServicesUtils.getInstance().callService(
					"UserService");
			ejbResponse = service.addPatient(user, locale);
			// Check the errors from service
			if (!ejbResponse.getErrors().isEmpty()) {
				return RegisterView.getInstance().getRegisterPatientViewWithError(userForm,
						ejbResponse);
			}
		} catch (final Exception e) {
			logger.error(CommonUtils.getInstance().getStackTrace(e));
			ejbResponse = new EjbResponse();
			ejbResponse.addError("error.calling.ejb");
			return RegisterView.getInstance().getRegisterPatientViewWithError(userForm,
					ejbResponse);
		}
		// If everything goes fine
		return CommonView.getInstance().getSuccessView("success.register.user");
	}

	/**
	 * Add a professional
	 * 
	 * @param userForm
	 *            The professional user object
	 * @param request
	 *            The request
	 * @param locale
	 *            The locale
	 * @return The view
	 * @throws ApplicationException
	 */
	@RequestMapping(value = "/add/professional", method = RequestMethod.POST)
	@PreAuthorize("isAnonymous()")
	public ModelAndView addProfessional(UserForm userForm, HttpServletRequest request,
			Locale locale) throws ApplicationException {
		if (!checkCaptcha(request)) {
			return RegisterView.getInstance().getRegisterProView(userForm, true);
		}
		final User user = new User();
		EjbResponse ejbResponse = null;
		try {
			BeanUtils.copyProperties(user, userForm);
			// Call the service for adding an user
			UserServiceRemote service = null;
			service = (UserServiceRemote) ServicesUtils.getInstance().callService(
					"UserService");
			ejbResponse = service.addProfessional(user, locale);
			// Check the errors from service
			if (!ejbResponse.getErrors().isEmpty()) {
				ejbResponse = new EjbResponse();
				ejbResponse.addError("error.calling.ejb");
				return RegisterView.getInstance().getRegisterProViewWithError(userForm,
						ejbResponse);
			}
		} catch (final Exception e) {
			logger.error(CommonUtils.getInstance().getStackTrace(e));
			return RegisterView.getInstance().getRegisterProViewWithError(userForm,
					ejbResponse);
		}
		// If everything goes fine
		return CommonView.getInstance().getSuccessView("success.register.user");
	}

	/**
	 * Check if the captcha entered by the user is valid
	 * 
	 * @param request
	 *            The request
	 * @return The result
	 */
	private boolean checkCaptcha(HttpServletRequest request) {
		final boolean captchaEnabled = Boolean.parseBoolean(PropertiesUtils.getInstance()
				.getProperty("recaptcha.enabled"));
		if (captchaEnabled) {
			final String challangeField = request.getParameter("recaptcha_challenge_field");
			final String responseField = request.getParameter("recaptcha_response_field");
			final String remoteAddress = request.getRemoteAddr();
			final ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
			final String privateKey = PropertiesUtils.getInstance().getProperty(
					"recaptcha.private.key");
			reCaptcha.setPrivateKey(privateKey);
			final ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(remoteAddress,
					challangeField, responseField);
			// If the Captcha is invalid
			if (!reCaptchaResponse.isValid()) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Confirm a registration
	 * 
	 * @param request
	 *            The request
	 * @param response
	 *            The response
	 * @param salt
	 *            The salt key
	 * @return The view
	 * @throws ApplicationException
	 */
	@RequestMapping(value = "/register/confirm", method = RequestMethod.GET)
	@PreAuthorize("isAnonymous()")
	public ModelAndView confirmRegistration(HttpServletRequest request,
			HttpServletResponse response, @RequestParam(value = "salt") String salt)
			throws ApplicationException {
		try {
			UserServiceRemote service = null;
			service = (UserServiceRemote) ServicesUtils.getInstance().callService(
					"UserService");
			final EjbResponse ejbResponse = service.confirmUser(salt);
			// Check the errors from service
			if (!ejbResponse.getErrors().isEmpty()) {
				return forbidden(response);
			}
		} catch (final Exception e) {
			return forbidden(response);
		}
		// If everything goes fine
		return CommonView.getInstance().getSuccessView("success.register.confirm");
	}

	/**
	 * Ask to the service to retrieve the account and send an email
	 * 
	 * @param user
	 *            The user object
	 * @param request
	 *            The request
	 * @param locale
	 *            The locale
	 * @return The view
	 * @throws ApplicationException
	 */
	@RequestMapping(value = "/retrieve/account", method = RequestMethod.POST)
	@PreAuthorize("isAnonymous()")
	public ModelAndView retrieveAccount(User user, HttpServletRequest request, Locale locale)
			throws ApplicationException {
		if (!checkCaptcha(request)) {
			return RegisterView.getInstance().getRegisterLostView(user, true);
		}
		EjbResponse ejbResponse = null;
		try {
			UserServiceRemote service = null;
			service = (UserServiceRemote) ServicesUtils.getInstance().callService(
					"UserService");
			ejbResponse = service.retrieveAccount(user.getMail(), locale);
			// Check the errors from service
			if (!ejbResponse.getErrors().isEmpty()) {
				return RegisterView.getInstance().getRegisterLostViewWithError(user,
						ejbResponse);
			}
		} catch (final Exception e) {
			logger.error(CommonUtils.getInstance().getStackTrace(e));
			ejbResponse = new EjbResponse();
			ejbResponse.addError("error.calling.ejb");
			return RegisterView.getInstance().getRegisterLostViewWithError(user, ejbResponse);
		}
		// If everything goes fine
		return CommonView.getInstance().getSuccessView("success.retrieve.account");
	}

	/**
	 * @param request
	 *            La request
	 * @return La vue affichant le formulaire d'ajout de patient
	 * @throws NamingException
	 */
	@RequestMapping("/register/lost")
	@PreAuthorize("isAnonymous()")
	public ModelAndView showRegisterLost(HttpServletRequest request, Locale locale)
			throws NamingException {
		final ModelAndView modelAndView = RegisterView.getInstance().getRegisterLostView(
				new User());
		final String message = messageSource.getMessage("label.register.lost", null, locale);
		modelAndView.addObject("pageTitle", message);
		return modelAndView;
	}

	/**
	 * @param request
	 *            La request
	 * @return La vue affichant le formulaire d'ajout de patient
	 * @throws NamingException
	 */
	@RequestMapping("/register/patient")
	@PreAuthorize("isAnonymous()")
	public ModelAndView showRegisterPatient(HttpServletRequest request, Locale locale)
			throws NamingException {
		final ModelAndView modelAndView = RegisterView.getInstance().getRegisterPatientView(
				new UserForm());
		final String message = messageSource
				.getMessage("label.register.patient", null, locale);
		modelAndView.addObject("pageTitle", message);
		return modelAndView;
	}

	/**
	 * @param request
	 *            La request
	 * @return La vue affichant le formulaire d'ajout de patient
	 * @throws NamingException
	 */
	@RequestMapping("/register/professional")
	@PreAuthorize("isAnonymous()")
	public ModelAndView showRegisterUserForm(HttpServletRequest request, Locale locale)
			throws NamingException {
		final ModelAndView modelAndView = RegisterView.getInstance().getRegisterProView(
				new UserForm());
		final String message = messageSource.getMessage("label.register.professional", null,
				locale);
		modelAndView.addObject("pageTitle", message);
		return modelAndView;
	}
}
